_Pragma("once");

#include <cstring>
#include <forward_list>

#include "SingletonTemplate.h"
#include "LoopManager.h"
#include "LoopStatus.h"
#include "LoopControlInfo.h"
#include "TaskScheduler.h"
#include "LoopControlInfoManager.h"
#include "TimedLoopCommandManager.h"
#include "common.h"
#include "LoopCommandType.h"
#include "NetworkListener.h"
#include "SystemStatus.h"


class LoopScheduler : public NetworkListener {
public:
    friend SingletonTemplate<LoopScheduler>;

    /** Default destructor */
    ~LoopScheduler();

    void schedule() {
        size_t length = mloopManager.updatePortCount();

        //   for (int k = 0; k < 256; ++k) {
        LoopControlInfoPtr loopCommand{new(length) LoopControlInfo{length, LoopStatus::AUTO_OFF}, LoopControlInfo::releaseMemory};
        mloopManager.changeAutoLoopStatus(loopCommand);

//            sleep(2);
//        }
    }


    void offline(INetwork* const network) override {
        msystemStatus = SystemStatus::OFFLINE;

        LOG_WARN("system offline, schedule offline and timed command...");

        scheduleOffline(true);

        const DateTimeUtility::ClockTime_t timeOfDay = std::chrono::system_clock::now().time_since_epoch();

        const DateTimeUtility::ClockTime_t beginOfDay = timeOfDay - timeOfDay % DateTimeUtility::TICK_COUNT_OF_DAY;
        const DateTimeUtility::ClockTime_t endOfDay = beginOfDay + DateTimeUtility::TICK_COUNT_OF_DAY;


        TaskRecordPtr pTaskRecord(new TaskRecord(TaskletInfo{std::bind(&LoopScheduler::scheduleOffline, this, false), nullptr}, endOfDay, DateTimeUtility::TICK_COUNT_OF_DAY, ETT_CIRCLE));
        addTaskRecord(pTaskRecord);
    }


    void dailyCheck();


    void addTaskRecord(TaskRecordPtr& pTaskRecord) {
        mtaskScheduler.addTask(pTaskRecord);
        mtaskRecords.emplace_front(pTaskRecord);
    }


   void online(INetwork* const network) override;



    void clear() {

        for (auto iterator = mtaskRecords.begin(); iterator != mtaskRecords.end(); ++iterator) {
            TaskRecordPtr pTaskRecord =iterator->lock();
            if (!pTaskRecord) {
                continue;
            }

            mtaskScheduler.cancelTask(pTaskRecord);
        }

        mtaskRecords.clear();
        mloopControlInfoManager.clear();
    }


    void scheduleOffline(const bool loadPrevControlInfo);

    void commitLoopCommandTask(std::shared_ptr<LoopControlInfoList> ploopControlInfos, const Task* pTask);

    void doLoopCommand(LoopControlInfoPtr loopControlInfoPtr, void* data);

/*
    suspendOfflineSystem(){
    if (SystemStatus::OFFLINE == loopScheduler.msystemStatus){
        loopScheduler.clear();
        }
    }

    resumeOfflineSystem(){
        if (SystemStatus::OFFLINE == loopScheduler.msystemStatus){
            loopScheduler.offline(nullptr);
        }
    }
*/


    volatile SystemStatus msystemStatus = SystemStatus::OFFLINE;
private:
    /** Default constructor */
    LoopScheduler();

    LoopManager& mloopManager;
    TaskScheduler& mtaskScheduler;
    LoopControlInfoManager& mloopControlInfoManager;
    TimedLoopCommandManager& mtimedLoopCommandManager;

    WorkerBase::PoolType* const mpool;
    //      task_routine_t mdoCommandCallback;

    std::forward_list<TaskRecordPtr::weak_type> mtaskRecords;
};


using LoopSchedulerSingleton = SingletonTemplate<LoopScheduler>;
